/*Copyright (C) 2009 - 2011 MASSART GAUTHIER and Careil Baptiste

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifndef POU_MAIN_POUSSE_CAISSE_H
# define POU_MAIN_POUSSE_CAISSE_H

# define TITRE_POUSSE_CAISSE "POUSSE CAISSE"
# define POU_MAT_ORG_X	(DEFAULT_SCREEN_SIZE_X / 2) - (POU_MAT_X / 2)
# define POU_MAT_ORG_Y	5
# define POU_MAT_X			50
# define POU_MAT_Y			20
/* Couleurs du pousse caisse */
# define POU_COL_MUR          COLOR_WHITE
# define POU_COL_JOUEUR       COLOR_CYAN
# define POU_COL_JOUEUR_TROU  COLOR_WHITE
# define POU_COL_CAISSE       COLOR_RED
# define POU_COL_CAISSE_TROU  COLOR_GREEN
# define POU_COL_TROU         COLOR_YELLOW
/* Touches du pousse caisse */
# define POU_KEY_QUIT    '0'
# define POU_KEY_RESTART 'r'
# define POU_KEY_UNDO    'u'
/* Touches d'édition de l'éditeur de niveau */
# define POU_KEY_EMUR		'm'
# define POU_KEY_EVIDE		'v'
# define POU_KEY_ETROU		't'
# define POU_KEY_ECAISSE	'c'
# define POU_KEY_EJOUEUR	'j'
/* Carractères affiché du pousse caisse */
# define POU_WCH_MUR     "▒"
# ifdef WIN32
#  define POU_WCH_JOUEUR "☺"
#  define POU_WCH_CAISSE "¤"
# else /* !WIN32 */
#  define POU_WCH_JOUEUR "☃"
#  define POU_WCH_CAISSE "☒"
# endif /* !WIN32 */
# define POU_WCH_TROU    "■"
/* Nom des fichiers temporaires */
# define POU_PATCH_TEMP_FILENAME "patch.lvl.tmp"
# define POU_DEST_TEMP_FILENAME  "dest.lvl.tmp"
/* Nom du fichier de niveaux officiel */
# define POU_LVLS_FUN		"niveaux/pou_fun.lvl"
# define POU_LVLS_EASY		"niveaux/pou_faciles.lvl"
# define POU_LVLS_INTER		"niveaux/pou_inter.lvl"
# define POU_LVLS_MEDIUM	"niveaux/pou_moyens.lvl"
# define POU_LVLS_HARD		"niveaux/pou_difficiles.lvl"

typedef enum POU_CASE_T {
	POU_VIDE = 0,
	POU_MUR = 1,
	POU_JOUEUR = 2,
	POU_CAISSE = 4,
	POU_TROU = 8
} POU_CASE_T;

typedef enum POU_QUIT_T {
	POU_WIN,
	POU_QUIT,
	POU_RESTART
} POU_QUIT_T;

typedef struct POU_COUPS_T {

	IPoint     *prev_player_pos;
	IPoint     *cur_player_pos;
	IPoint     *cur_caisse_pos;
	POU_CASE_T *prev_player_cel;
	POU_CASE_T *cur_player_cel;
	POU_CASE_T *cur_caisse_cel;
} POU_COUPS_T;

typedef struct POU_INF_T {
	IPoint pos_joueur;
	IPoint pos_inf;
	int nb_caisses;
	int nb_caisses_restantes;
	int nb_trous;
	int nb_deplacements;
	Container coups;
} POU_INF_T;

/** man_pousse_caisse.c **/
/* Afiche le manuel du pousse caisse
*/
void pou_man(void);

/** level_editor_pc.c **/

/* Menu principal de l'éditeur de niveaux
*/
void pou_menu_level_editor();

/* Permet de choisir le pack de niveaux à éditer
*/
void pou_choose_level_pack_to_edit();

/* Permet de choisir le niveau à éditer
** \param file     Le pack de niveaux à éditer
** \param filename Le nom du pack de niveaux
*/
void pou_choose_level_to_edit(FILE *file, char *filename);

/* Permet de créer un level
*/
void pou_create_level();

/* Permet de demander le nom de l'auteur et le nom du niveau à
** l'utilisateur.
** \param lvl_name    Le nom du niveau de taille `len'
** \param author_name Le nom de l'auteur du niveau de taille `len'
** \param len         La taille des chaines de caractères
**                    `lvl_name' et `author_name'
*/
void pou_edit_level_info(char *lvl_name, char *author_name, size_t len);

/* Permet d'ajouter un niveau à la fin d'un pack
** \param lvl_pack_filename Le nom du pack de niveaux
** \param matrix            La matrice de jeu
** \param lvl_name          Le nom du niveau
** \param author_name       Le nom de l'auteur du niveau
** \return                  0 en cas de succès
**                          1 en cas c'erreur
*/
int pou_append_to_lvl_pack(const char *lvl_pack_filename,
													 POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y],
													 const char *lvl_name,
													 const char *author_name);

/* Permet de créer un pack de niveaux
*/
int pou_create_level_pack();

/* Boucle principale de l'éditeur. Ses deux arguments
** doivent être corectement initialisé.
** \param matrix La matrice à modifier.
** \param inf    Les informations sur la matrice.
** \return       0 Si les modifications sont abandonnées
**               1 Si les modifications doivent être sauvegardées
*/
int pou_level_editor(POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y], POU_INF_T *inf);

/* Permet de modifier la position du curseur sous ordre
** du joueur
** \param key        La touche pressée par le joueur
** \param cursor_pos La position du curseur.
*/
void pou_move_cursor(int key, IPoint *cursor_pos);

/* Permet d'éditer la matrice sous ordre du joueur
** \param matrix     La matrice du jeu
** \param key        La touche pressée par le joueur
** \param cursor_pos La position du curseur
** \param inf        Les informations sur le jeu.
*/
void pou_edit_matrix(POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y], int key, IPoint *cursor_pos, POU_INF_T *inf);

/** menu_pousse_caisse.c **/

/* Menu principale du pousse caisse
*/
void pou_menu(void);

/* Fonction demandant au joueur s'il veut
** jouer aux niveaux officiel ou à ses propres
** packs de niveaux.
*/
void pou_menu_choix_type_niveau();

/* Fonction permettant au joueur de jouer les niveaux officiels
*/
void pou_play_base_levels();

/* Fonction permettant au joueur de jouer à ses niveaux personnels.
*/
void pou_play_custom_levels();

/* Fonction demandant au joueur quel niveau il veut jouer.
** \param file Le fichier ouvert du pack de niveau.
*/
void pou_select_level(FILE *file);

/** main_pousse_caisse.c **/

/* boucle principale du jeu.
** Elle se charge d'afficher la matrice et de traiter les entrées
** de l'utilsateur.
** \param matrix La matrice du jeu initialisée.
** \param inf    Les informations liées à la partie, initialisées.
** \return       Un membre de l'énumération POU_QUIT_T
**               POU_QUIT    Si l'utilisateur a quitté
**               POU_WIN     Si l'utilisateur a gagné la partie
**               POU_RESTART Si le joueur a demander le redémarrage de la partie.
*/
POU_QUIT_T pou_play(POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y], POU_INF_T *inf);

/* Fonction permettant de péplacer le joueur sur la matrice
** en fonction de `key'.
** \param key     La touche saisite par l'utilisateur
** \param matrice La matrice du jeu
** \param inf     Les divers informations liées à la partie
*/
void pou_move_player(POU_CASE_T matrice[POU_MAT_X][POU_MAT_Y], int key, POU_INF_T *inf);

/* Permet de valider, effectuer et afficher un mouvement.
** \param inf  Les informations sur la partie
** \param coup Le coup à jouer.
*/
void pou_valid_move(POU_INF_T *inf, POU_COUPS_T *coup);

/* Anulle un coups stocké dans inf->coups
** \param inf Les information liées à la partie
*/
void pou_undo(POU_INF_T *inf);

/* Permet de libéré un coup préalablement alloué.
** \param coup Le coup à libérer.
*/
void pou_free_coup(POU_COUPS_T *coup);

/** pou_affichage.c */

/* Fonction affichant l'écran de jeu
** \param matrix La matrice du jeu
** \param inf    Les informations relatives à la partie.
*/
void pou_display_game(POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y], POU_INF_T *inf);

/* Fonction affichant l'écran d'édition
** \param matrix La matrice du jeu
** \param inf    Les informations sur la partie
*/
void pou_display_editor(POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y], POU_INF_T *inf);

/* Fonction affichant la matrice
** \param matrix La matrice à afficher
*/
void pou_display_matrix(POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y]);

/* Fonction affichant la légende
*/
void pou_display_legend();

/* Fonction rafraichissant les information sur le jeu
** \param inf Les informations relatives à la partie.
*/
void pou_refresh_inf(POU_INF_T *inf);

/* Fonction rafraichissant les informations sur l'édition en cours
** \param inf Les informations sur la partie.
*/
void pou_refresh_editor_inf(POU_INF_T *inf);

/* Fonction rafraichissant la valeur d'une case
** \param pos   La position de la case à rafraichire dans la matrice
** \param value La nouvelle valeur de la case
*/
void pou_refresh_case(IPoint *pos, POU_CASE_T value);

/* Fonction rafraichissant les valeurs des cases d'un coup
** \param coup Le coup à rafraichir
*/
void pou_refresh_coup(POU_COUPS_T *coup);

/* Fonction permettant d'afficher une case à la position
** courante du curseur.
*/
void pou_display_case(POU_CASE_T value);

/** pou_file_matrix.c **/

/* Parse un fichier dans le but d'initialiser la matrice
** et les info sur la partie. Cette fonction n'initialise que
** les membres nb_caisses, nb_caisses_restantes et pos_joueur
** de inf.
** \param file   Le fichier de pack de niveaux (ouvert)
** \param level  Le level à charger
** \param matrix La matrice à initialiser (allouée)
** \param inf    Les informations sur la partie (allouées)
** \return       0 en cas de succès
**               1 en cas d'une erreur de parsage
*/
int pou_parse_file(FILE *file, int level, POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y], POU_INF_T *inf);

/* Permet de parser un fichier de pack de niveau dans le but
** d'en retirer la liste des niveaux et la liste des auteurs
** NOTE: Les arguments lvl_list et author_list sont modifiés
**       et allouées par la fonction. Il faudra les libérer
**       après usage.
** \param file        Le fichier de pack de niveaux (ouvert)
** \param lvl_list    Un pointeur sur une chaine de caractère où
**                    sera stockée la liste des niveaux. La chaine
**                    sera allouée au fur et à mesure.
**                    /!\ à libérer après utilisation.
** \param author_list Un poiteur sur une chaine de caractère où
**                   sera stockée la liste des auteurs. La chaine
**                   sera allouée au fur et à mesure.
**                   /!\ à libérer après utilisation.
** \return           0 en cas d'erreur de parsage
**                   Le nombre de lvl si tout s'est bien passé.
*/
int pou_get_level_list(FILE *file, char **lvl_list, char **author_list);

/* Permet de sauvegarder un niveau dans un fichier
** à partir de sa matrice.
** \param level_file  Le fichier ouvert en écriture où sera ajouter le niveau
** \param matrix      La matrice du niveau ne comportant pas de case combinée
**                    (ex : pas de POU_JOUER|POU_TROU)
** \param author_name Le nom de l'auteur du niveau (pas plus de 50 ch)
** \param level_name  Le nom du niveau (pas plus de 50 ch)
*/
void pou_save_level(FILE *level_file,
										POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y],
										const char *author_name,
										const char *level_name);

/* Permet d'ecrire l'integralite d'un niveau dans une chaine de caractere
 * \param matrix	La matrice du niveau ne comportant pas de case combine
 *              	(ex : pas de POU_JOUEUR|POU_TROU)
 * \param author	Le nom de l'auteur du niveau (pas plus de 50ch)
 * \param name  	Le nom du niveau (pas plus de 50ch)
 * \return      	Une chaine de caractere alloue contenant le niveau
 * \return      	NULL en cas d'erreur.
*/
char *pou_level_to_string(POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y],
													const char *author,
													const char *name);

/* Permet d'initialiser la matice et les informations
** sur la partie avec les données par défaut
** \param matrix La matrice du jeu
** \param inf    Les informations relative à la partie.
*/
void pou_init_to_default(POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y], POU_INF_T *inf);

#endif /* !POU_MAIN_POUSSE_CAISSE_H */
